package vn.com.bookstore.utils;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import vn.com.bookstore.model.vo.CardVO;


public class CardHelper {

	private static final Logger logger = LoggerFactory
			.getLogger(CardHelper.class);

	private String algorithmName = "MD5";
	private String func = "CardCharge";
	private String version = "2.0";
	private String merchantPassword = "pavi@b00k";
	private String result;
	public static final String URL_API = "https://www.nganluong.vn/mobile_card.api.post.v2.php"; 
	public static final String MERCHANT_ID = "30581";
	public static final String MERCHANT_ACCOUNT = "pavibook@nxbthoidai.vn";
	public static final String CODE_SUCCESS = "00";
	private CardVO sendCard;
	private CardVO resultCard;
	/**
	 * 
	 * @param pinCar
	 *            - d code of prepaid card
	 * @param serialCard
	 *            - serial number of prepaid card
	 * @param typeCard
	 *            - VMS: MobiFone card, VNP: VinaPhone card, VIETTEL: Viettel
	 *            card
	 * @param refCode
	 *            - Only code is corresponding with a buyer at merchant (for ex:
	 *            bill number, account name, account id..)
	 * @param clientFullname
	 *            - Full name of buyer at merchant
	 * @param clientEmail
	 *            - Email of buyer at merchant
	 * @param clientMobile
	 *            - Phone number of buyer at merchant
	 */
	public void checkout(String pinCard, String serialCard, String typeCard,
			String refCode, String clientFullname, String clientEmail,
			String clientMobile) {
		
		sendCard = new CardVO();
		
		sendCard.setMerchantId(MERCHANT_ID);
		sendCard.setMerchantAccount(MERCHANT_ACCOUNT);
		
		merchantPassword = hash(sendCard.getMerchantId()+"|"+merchantPassword);

		sendCard.setPinCard(pinCard);
		sendCard.setSerialCard(serialCard);
		sendCard.setTypeCard(typeCard);
		sendCard.setRefCode(refCode);
		sendCard.setClientFullname(clientFullname);
		sendCard.setClientEmail(clientEmail);
		sendCard.setClientMobile(clientMobile);
		
		String params = buildParamsWithClientInfo();
		
		process(params);
		
	}
	
	
	/**
	 * 
	 * @param pinCar
	 *            - d code of prepaid card
	 * @param serialCard
	 *            - serial number of prepaid card
	 * @param typeCard
	 *            - VMS: MobiFone card, VNP: VinaPhone card, VIETTEL: Viettel
	 *            card
	 * @param refCode
	 *            - Only code is corresponding with a buyer at merchant (for ex:
	 *            bill number, account name, account id..)
	 */
	public void checkout(String pinCard, String serialCard, String typeCard,
			String refCode) {
		sendCard = new CardVO();
		
		sendCard.setMerchantId(MERCHANT_ID);
		sendCard.setMerchantAccount(MERCHANT_ACCOUNT);
		
		merchantPassword = hash(sendCard.getMerchantId()+"|"+merchantPassword);

		sendCard.setPinCard(pinCard);
		sendCard.setSerialCard(serialCard);
		sendCard.setTypeCard(typeCard);
		sendCard.setRefCode(refCode);
		
		String params = buildParams();
		
		process(params);
		
	}
	
	private void process(String params){
		logger.debug("process: in");
		
		this.result = excutePost(URL_API, params,"POST");
		logger.info("result: "+result);
		String[] splitResult = this.result.split("\\|");
		resultCard = new CardVO();
		resultCard.setErrorCode(splitResult[0]);
		
		if (splitResult[0].equals(CODE_SUCCESS)){
//			error_code|merchant_id|merchant_account|
//			pin_card|card_serial|type_card|ref_code|
//			client_fullname|client_email|client_mobile|
//ard_amount|transaction _amount|transaction_id
			resultCard.setMerchantId(splitResult[1]);
			resultCard.setMerchantAccount(splitResult[2]);
			resultCard.setPinCard(splitResult[3]);
			resultCard.setSerialCard(splitResult[4]);
			resultCard.setTypeCard(splitResult[5]);
			resultCard.setRefCode(splitResult[6]);
			try{
				resultCard.setClientFullname(splitResult[7]);
				resultCard.setClientEmail(splitResult[8]);
				resultCard.setClientMobile(splitResult[9]);
				resultCard.setTransactionAmount(Integer.parseInt(splitResult[10]));
				resultCard.setTransactionAmount(Integer.parseInt(splitResult[11]));
				resultCard.setTransactionId(Integer.parseInt(splitResult[12]));
			}catch(Exception ex){
				logger.debug("Some param is null");
			}
			
			logger.debug("process: out");
		}
	}

	public String getErrorMessage() {
		
//		this.result = "error_code|merchant_id|merchant_account|pin_card|card_serial|type_card|ref_code|client_fullname|client_email|client_mobile|card_amount|transaction _amount|transaction_id";

		Map<String, String> mapMessage = new HashMap<String, String>();
		
		mapMessage.put("00", "Giao dịch thành công");
		mapMessage.put("99","Lỗi, tuy nhiên lỗi chưa được định nghĩa hoặc chưa xác định được nguyên nhân");
		mapMessage.put("01","Lỗi, địa chỉ IP truy cập API của NgânLượng.vn bị từ chối");
		mapMessage.put("02","Lỗi, tham số gửi từ merchant tới NgânLượng.vn chưa chính xác (thường sai tên tham số hoặc thiếu tham số)");
		mapMessage.put("03","Lỗi, Mã merchant không tồn tại hoặc merchant đang bị khóa kết nối tới NgânLượng.vn");
		mapMessage.put("04","Lỗi, Mã checksum không chính xác (lỗi này thường xảy ra khi mật khẩu giao tiếp giữa merchant và NgânLượng.vn không chính xác, hoặc cách sắp xếp các tham số trong biến params không đúng)");
		mapMessage.put("05","Tài khoản nhận tiền nạp của merchant không tồn tại");
		mapMessage.put("06","Tài khoản nhận tiền nạp của merchant đang bị khóa hoặc bị phong tỏa, không thể thực hiện được giao dịch nạp tiền");
		mapMessage.put("07", "Thẻ đã được sử dụng ");
		mapMessage.put("08", "Thẻ bị khóa");
		mapMessage.put("09", "Thẻ hết hạn sử dụng");
		mapMessage.put("10", "Thẻ chưa được kích hoạt hoặc không tồn tại");
		mapMessage.put("11", "Mã thẻ sai định dạng");
		mapMessage.put("12", "Sai số serial của thẻ");
		mapMessage.put("13", "Mã thẻ và số serial không khớp");
		mapMessage.put("14", "Thẻ không tồn tại");
		mapMessage.put("15", "Thẻ không sử dụng được");
		mapMessage.put("16","Số lần thử (nhập sai liên tiếp) của thẻ vượt quá giới hạn cho phép");
		mapMessage.put("17","Hệ thống Telco bị lỗi hoặc quá tải, thẻ chưa bị trừ");
		mapMessage.put("18","Hệ thống Telco bị lỗi hoặc quá tải, thẻ có thể bị trừ, cần phối hợp với NgânLượng.vn để tra soát");
		mapMessage.put("19","Kết nối từ NgânLượng.vn tới hệ thống Telco bị lỗi, thẻ chưa bị trừ (thường do lỗi kết nối giữa NgânLượng.vn với Telco, ví dụ sai tham số kết nối, mà không liên quan đến merchant)");
		mapMessage.put("20","Kết nối tới telco thành công, thẻ bị trừ nhưng chưa cộng tiền trên NgânLượng.vn");
		
		return mapMessage.get(resultCard.getErrorCode());
	}

	private String buildParamsWithClientInfo() {

		return "func=" + func + "&version=" + version + "&merchant_id="
				+ sendCard.getMerchantId() + "&merchant_account=" + sendCard.getMerchantAccount()
				+ "&merchant_password=" + merchantPassword + "&pin_card="
				+ sendCard.getPinCard() + "&card_serial=" + sendCard.getSerialCard() + "&type_card="
				+ sendCard.getTypeCard() + "&ref_code=" + sendCard.getRefCode() + "&client_fullname="
				+ sendCard.getClientFullname() + "&client_email=" + sendCard.getClientEmail()
				+ "&client_mobile=" + sendCard.getClientMobile();

	}
	
	private String buildParams() {

		return "func=" + func + "&version=" + version + "&merchant_id="
				+ sendCard.getMerchantId() + "&merchant_account=" + sendCard.getMerchantAccount()
				+ "&merchant_password=" + merchantPassword + "&pin_card="
				+ sendCard.getPinCard() + "&card_serial=" + sendCard.getSerialCard() + "&type_card="
				+ sendCard.getTypeCard() + "&ref_code=" + sendCard.getRefCode();

	}

	private String hash(String messages) {
		if (messages == null)
			throw new NullPointerException();

		StringBuffer result = null;
		byte[] data = messages.getBytes();
		try {
			MessageDigest md = MessageDigest.getInstance(algorithmName);
			md.reset();
			md.update(data);
			byte[] msgDigest = md.digest();
			result = new StringBuffer();
			for (int i = 0; i < msgDigest.length; i++) {
				String hex = Integer.toHexString(0xff & msgDigest[i]);
				if (hex.length() == 1)
					result.append("0");
				result.append(hex);
			}
		} catch (NoSuchAlgorithmException ex) {
			logger.debug(ex.toString());
		}
		return result.toString();
	}

	public String excutePost(String targetURL, String urlParameters, String requestMethod) {
		URL url;
		HttpURLConnection connection = null;
		try {
			// Create connection
			url = new URL(targetURL);
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod(requestMethod);
			connection.setRequestProperty("Content-Type",
					"application/x-www-form-urlencoded");

			if(urlParameters != null)
			connection.setRequestProperty("Content-Length",
					"" + Integer.toString(urlParameters.getBytes().length));
			connection.setRequestProperty("Content-Language", "en-US");

			connection.setUseCaches(false);
			connection.setDoInput(true);
			connection.setDoOutput(true);

			// Send request
			DataOutputStream wr = new DataOutputStream(
					connection.getOutputStream());
			if(urlParameters != null)
				wr.writeBytes(urlParameters);
			wr.flush();
			wr.close();

			// Get Response
			InputStream is = connection.getInputStream();
			BufferedReader rd = new BufferedReader(new InputStreamReader(is));
			String line;
			StringBuffer response = new StringBuffer();
			while ((line = rd.readLine()) != null) {
				response.append(line);
				response.append("\r");
			}
			rd.close();
			return response.toString();

		} catch (Exception e) {

			e.printStackTrace();
			return null;

		} finally {

			if (connection != null) {
				connection.disconnect();
			}
		}
	}

	public String getAlgorithmName() {
		return algorithmName;
	}

	public void setAlgorithmName(String algorithmName) {
		this.algorithmName = algorithmName;
	}

	public String getFunc() {
		return func;
	}

	public void setFunc(String func) {
		this.func = func;
	}

	public String getVersion() {
		return version;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	public String getMerchantPassword() {
		return merchantPassword;
	}

	public void setMerchantPassword(String merchantPassword) {
		this.merchantPassword = merchantPassword;
	}

	public String getResult() {
		return result;
	}

	public void setResult(String result) {
		this.result = result;
	}


	public CardVO getSendCard() {
		return sendCard;
	}


	public void setSendCard(CardVO sendCard) {
		this.sendCard = sendCard;
	}


	public CardVO getResultCard() {
		return resultCard;
	}


	public void setResultCard(CardVO resultCard) {
		this.resultCard = resultCard;
	}
	
}